SPB Git

Repository Public

page.tsx 14.5 KB 240 lines tsx

1import type { Metadata } from "next";2import Link from "next/link";3import { Topology } from "@/components/infrastructure/Topology";4import { boardNodes } from "@/components/live/board-nodes";5import { LiveOverview, LivePill } from "@/components/live/LiveOverview";6import { chipShort } from "@/components/nodes/bits";7import { Photo } from "@/components/ui/Photo";8import { Arrow, SectionHead } from "@/components/ui/Section";9import { nodes, photoById, photos, research, site } from "@/lib/data";10import { formatDate, formatNumber, getDict, type Locale } from "@/lib/i18n";11import { aggregate } from "@/lib/inventory";12import { pageMetadata } from "@/lib/seo";1314type Props = { params: Promise<{ locale: Locale }> };1516export async function generateMetadata({ params }: Props): Promise<Metadata> {17  return pageMetadata((await params).locale, "home", "");18}1920export default async function Home({ params }: Props) {21  const { locale } = await params;22  const t = getDict(locale);23  const h = t.home;24  const agg = aggregate(nodes);25  const hero = photoById("rack-a")!;26  const wide = photoById("rack-b")!;27  const laptops = agg.byFamily.filter((f) => f.family.startsWith("MacBook")).reduce((a, f) => a + f.count, 0);28  const counts = { studio: agg.byFamily.find((f) => f.family === "Mac Studio")?.count ?? 0, mini: agg.byFamily.find((f) => f.family === "Mac mini")?.count ?? 0, laptop: laptops };29  const featured = research.filter((r) => r.status === "completed").slice(0, 3);3031  const metrics: { value: string; unit?: string; label: string; sub: string }[] = [{ value: formatNumber(agg.documented, locale), label: h.metrics.nodes, sub: h.metrics.nodesSub(agg.active) }];32  if (agg.unifiedMemoryGB !== null) metrics.push({ value: formatNumber(agg.unifiedMemoryGB, locale), unit: t.common.gb, label: h.metrics.memory, sub: h.metrics.memorySub });33  if (agg.cpuCores !== null) metrics.push({ value: formatNumber(agg.cpuCores, locale), label: h.metrics.cpu, sub: agg.gpuCores !== null ? `${formatNumber(agg.gpuCores, locale)} ${h.metrics.gpu}` : h.metrics.gpuPartial });34  metrics.push({ value: site.measuredLinkRate, label: h.metrics.network, sub: h.metrics.networkSub });3536  return (37    <>38      {/* Hero: headline and live summary first, the real photograph in its native portrait framing beside it. */}39      <section className="relative overflow-hidden">40        <div aria-hidden="true" className="pointer-events-none absolute inset-x-0 top-0 h-[32rem] bg-[radial-gradient(60rem_26rem_at_20%_-10%,rgb(29_95_209/0.10),transparent)]" />41        <div className="shell relative grid items-center gap-10 pb-12 pt-8 md:pt-14 lg:grid-cols-12 lg:gap-12 lg:pb-20">42          <div className="lg:col-span-7">43            <div className="hero-in"><LivePill locale={locale} /></div>44            <p className="eyebrow hero-in tick mt-7">{h.eyebrow}</p>45            <h1 className="display hero-in-2 mt-5 text-[clamp(2.5rem,1rem+6.4vw,5.75rem)]">46              {locale === "fr" ? <>La recherche aux limites d&apos;<em>Apple&nbsp;Silicon.</em></> : <>Research at the edge of <em>Apple&nbsp;Silicon.</em></>}47            </h1>48            <p className="hero-in-3 mt-6 max-w-[38ch] text-[1.1875rem] leading-snug tracking-[-0.01em] text-fg md:text-[1.375rem]">{h.lede}</p>49            <p className="hero-in-3 prose-tech mt-4 max-w-[52ch]">{h.support}</p>50            <div className="hero-in-3 mt-8 flex flex-col gap-3 sm:flex-row sm:flex-wrap">51              <Link href={`/${locale}/live`} className="btn btn-primary">{t.live.home.link} <Arrow /></Link>52              <Link href={`/${locale}#infrastructure`} className="btn btn-ghost">{h.ctaExplore}</Link>53              <Link href={`/${locale}/access`} className="btn btn-ghost">{h.ctaAccess}</Link>54            </div>55          </div>56          <figure className="relative lg:col-span-5">57            <div className="photo-frame relative aspect-[4/5] w-full sm:aspect-[3/2] lg:aspect-[3/4]">58              <Photo photo={hero} locale={locale} fill priority quality={60} sizes="(min-width: 1024px) 42vw, 92vw" />59              <div className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black/75 via-transparent to-transparent" aria-hidden="true" />60              <figcaption className="absolute inset-x-0 bottom-0 flex items-end justify-between gap-4 p-4 font-mono text-[0.6875rem] tracking-[0.06em] text-white md:p-5">61                <span>{h.heroCaption}</span>62                <span className="hidden sm:inline">01 / {String(photos.length).padStart(2, "0")}</span>63              </figcaption>64            </div>65          </figure>66        </div>67      </section>6869      {/* Verified metrics: computed from the inventory, never hardcoded. */}70      <section aria-labelledby="metrics-h">71        <div className="shell pb-4">72          <div className="flex flex-wrap items-baseline justify-between gap-3">73            <h2 id="metrics-h" className="label">{h.metrics.heading}</h2>74            <p className="label">{h.metrics.asOf} <time dateTime={site.inventoryVerifiedAt} className="text-body">{formatDate(site.inventoryVerifiedAt, locale)}</time></p>75          </div>76          <ul className="mt-5 grid grid-cols-2 gap-3 lg:grid-cols-4" data-testid="metrics">77            {metrics.map((m) => (78              <li key={m.label} className="card p-4 md:p-6">79                <p>80                  <span className="num block text-[clamp(2rem,1.3rem+2.8vw,3.5rem)] font-semibold leading-none tracking-[-0.045em]">81                    {m.value}{m.unit ? <span className="ml-1.5 text-[0.4em] font-normal tracking-normal text-mute">{m.unit}</span> : null}82                  </span>{" "}83                  <span className="mt-3 block text-[0.9375rem] font-medium text-fg">{m.label}</span>84                </p>85                <p className="mt-1 text-[0.8125rem] leading-snug text-mute">{m.sub}</p>86              </li>87            ))}88          </ul>89          <p className="mt-5 max-w-[78ch] text-[0.8125rem] leading-relaxed text-mute">{h.metrics.note}</p>90        </div>91      </section>9293      {/* Live now */}94      <section aria-labelledby="live-now-h" className="py-14 md:py-20">95        <div className="shell">96          <div className="flex flex-col gap-4 md:flex-row md:items-end md:justify-between">97            <div>98              <p className="eyebrow">{t.live.home.eyebrow}</p>99              <h2 id="live-now-h" className="h2 mt-4">{t.live.home.title}</h2>100              <p className="prose-tech mt-3">{t.live.home.intro}</p>101            </div>102            <Link className="btn btn-ghost shrink-0 self-start md:self-auto" href={`/${locale}/live`}>{t.live.home.link} <Arrow /></Link>103          </div>104          <div className="mt-8"><LiveOverview nodes={boardNodes(nodes, t)} locale={locale} /></div>105        </div>106      </section>107108      {/* Built from real machines */}109      <section id="infrastructure" className="scroll-mt-20 border-t border-line py-16 md:py-28">110        <div className="shell grid gap-10 lg:grid-cols-12 lg:gap-12">111          <div className="reveal lg:col-span-5 lg:pt-10">112            <p className="eyebrow">{h.real.eyebrow}</p>113            <h2 className="h2 mt-5">{h.real.title}</h2>114            {h.real.body.map((p) => <p key={p.slice(0, 24)} className="prose-tech mt-5">{p}</p>)}115            <p className="mt-8"><Link className="link inline-flex items-center gap-2" href={`/${locale}/gallery`}>{h.real.link} <Arrow /></Link></p>116          </div>117          <figure className="reveal lg:col-span-7">118            <div className="photo-frame relative aspect-[4/5] md:aspect-[5/4]">119              <div className="parallax absolute inset-0">120                <Photo photo={wide} locale={locale} fill sizes="(min-width: 1024px) 56vw, 100vw" focus="50% 58%" />121              </div>122            </div>123            <figcaption className="label mt-3">{wide.title[locale]}</figcaption>124          </figure>125        </div>126      </section>127128      {/* Topology */}129      <section className="border-y border-line bg-surface py-16 md:py-24">130        <div className="shell">131          <SectionHead eyebrow={h.topology.eyebrow} title={h.topology.title} intro={h.topology.intro} />132          <p className="label mt-10 md:ml-[25%]">{h.topology.hint}</p>133          <div className="mt-6"><Topology locale={locale} counts={counts} linkRate={`${site.measuredLinkRate}`} /></div>134          <p className="mt-10"><Link className="link inline-flex items-center gap-2" href={`/${locale}/architecture`}>{h.topology.link} <Arrow /></Link></p>135        </div>136      </section>137138      {/* Hardware families */}139      <section className="py-16 md:py-24">140        <div className="shell">141          <SectionHead eyebrow={h.families.eyebrow} title={h.families.title} intro={h.families.intro} />142          <ul className="mt-10 grid grid-cols-2 gap-3 lg:grid-cols-4">143            {agg.byFamily.map((f) => {144              const chips = [...new Set(nodes.filter((n) => n.family === f.family && n.chip).map((n) => chipShort(n.chip!)))];145              return (146                <li key={f.family} className="reveal">147                  <Link href={`/${locale}/nodes?family=${encodeURIComponent(f.family)}`} className="card card-hover group flex h-full flex-col p-4 md:p-6">148                    <p className="num text-[2.5rem] font-semibold leading-none tracking-[-0.05em] md:text-[3.25rem]">{f.count}</p>149                    <h3 className="mt-3 text-lg font-semibold tracking-[-0.02em] md:text-xl">{t.common.families[f.family]}</h3>150                    <p className="mt-1 text-[0.875rem] text-mute">{h.families.units(f.count)}</p>151                    <p className="num mt-5 border-t border-line pt-4 font-mono text-[0.75rem] text-body">{f.memoryGB !== null ? `${formatNumber(f.memoryGB, locale)} ${t.common.gb} ${h.families.memory}` : t.common.notDocumented}</p>152                    <p className="mt-2 font-mono text-[0.75rem] leading-relaxed text-mute">{chips.join(" · ")}</p>153                    <span className="mt-auto flex items-center gap-2 pt-5 text-[0.875rem] text-body group-hover:text-accent">{t.common.viewAll} <Arrow /></span>154                  </Link>155                </li>156              );157            })}158          </ul>159          <p className="mt-8"><Link className="link inline-flex items-center gap-2" href={`/${locale}/nodes`}>{h.families.link} <Arrow /></Link></p>160        </div>161      </section>162163      {/* Research themes */}164      <section className="border-t border-line py-16 md:py-24">165        <div className="shell">166          <SectionHead eyebrow={h.themes.eyebrow} title={h.themes.title} />167          <ul className="mt-10 grid gap-3 md:grid-cols-2 lg:grid-cols-3">168            {h.themes.items.map((it, i) => (169              <li key={it.key} className="reveal card p-5 md:p-6">170                <div className="flex items-center justify-between gap-3">171                  <span className="num font-mono text-[0.6875rem] tracking-[0.1em] text-mute">{String(i + 1).padStart(2, "0")}</span>172                  <span className={`rounded-full px-2.5 py-1 font-mono text-[0.625rem] uppercase tracking-[0.1em] ${it.state === "planned" ? "bg-accent-soft text-accent" : "bg-ok/10 text-ok"}`}>{it.state === "planned" ? h.themes.planned : h.themes.active}</span>173                </div>174                <h3 className="mt-4 text-xl font-semibold tracking-[-0.02em]">{it.title}</h3>175                <p className="mt-2.5 text-[0.9375rem] leading-relaxed text-body">{it.body}</p>176              </li>177            ))}178          </ul>179        </div>180      </section>181182      {/* Selected experiments */}183      <section className="border-y border-line bg-surface py-16 md:py-24">184        <div className="shell">185          <SectionHead eyebrow={h.experiments.eyebrow} title={h.experiments.title} intro={h.experiments.intro} />186          <ol className="mt-10 divide-y divide-line border-y border-line">187            {featured.map((r) => (188              <li key={r.id} className="reveal grid gap-3 py-7 md:grid-cols-12 md:gap-8">189                <p className="label md:col-span-3">{r.reference?.label} · <time dateTime={r.date}>{formatDate(r.date, locale)}</time></p>190                <div className="md:col-span-9">191                  <h3 className="max-w-[44ch] text-[1.1875rem] font-semibold leading-snug tracking-[-0.015em]">192                    {r.reference ? <a className="link" href={r.reference.url} rel="noopener" lang="en">{r.title.en}</a> : r.title[locale]}193                  </h3>194                  <p className="mt-3 max-w-[70ch] text-[0.9375rem] leading-relaxed text-body"><span className="text-mute">{h.experiments.clusterUse} — </span>{r.clusterUse[locale]}</p>195                </div>196              </li>197            ))}198          </ol>199          <p className="mt-8 flex flex-wrap gap-x-8 gap-y-3">200            <Link className="link inline-flex items-center gap-2" href={`/${locale}/research`}>{h.experiments.link} <Arrow /></Link>201            <Link className="link inline-flex items-center gap-2" href={`/${locale}/benchmarks`}>{h.experiments.benchLink} <Arrow /></Link>202          </p>203        </div>204      </section>205206      {/* Photographic journal */}207      <section className="py-16 md:py-24">208        <div className="shell">209          <SectionHead eyebrow={h.gallery.eyebrow} title={h.gallery.title} />210          <ul className="mt-10 grid grid-cols-2 gap-3 md:grid-cols-4 md:gap-5">211            {photos.map((p, i) => (212              <li key={p.id} className={`reveal ${i % 2 ? "md:mt-12" : ""}`}>213                <Link href={`/${locale}/gallery`} className="photo-frame group relative block aspect-[3/4]" aria-label={p.title[locale]}>214                  <Photo photo={p} locale={locale} fill sizes="(min-width: 768px) 22vw, 48vw" className="transition-transform duration-700 group-hover:scale-[1.03]" />215                </Link>216              </li>217            ))}218          </ul>219          <p className="mt-8"><Link className="link inline-flex items-center gap-2" href={`/${locale}/gallery`}>{h.gallery.link} <Arrow /></Link></p>220        </div>221      </section>222223      {/* Access invitation: modest, not a sales call to action */}224      <section className="shell">225        <div className="card grid gap-6 p-6 md:grid-cols-12 md:p-12">226          <p className="eyebrow md:col-span-3 md:pt-3">{h.access.eyebrow}</p>227          <div className="reveal md:col-span-9">228            <h2 className="h2 max-w-[20ch]">{h.access.title}</h2>229            <p className="prose-tech mt-5">{h.access.body}</p>230            <p className="mt-7 flex flex-wrap items-center gap-x-8 gap-y-4">231              <Link href={`/${locale}/access`} className="btn btn-primary">{h.access.link} <Arrow /></Link>232              <a className="link" href={`mailto:${site.contactEmail}`}>{site.contactEmail}</a>233            </p>234          </div>235        </div>236      </section>237    </>238  );239}240
Files main
Menu

Theme